//
// Created by hay boy on 2022/6/26.
//

#ifndef ALGORITHMS_ARRAYSTACK_H
#define ALGORITHMS_ARRAYSTACK_H

#include <sstream>
#include "Stack.h"
#include "../exception/illegalParameterValue.h"
#include "../linearList/LinearList.h"
template<class T>
class ArrayStack :public Stack<T>{
public:
    explicit ArrayStack(int initialCapacity=10);
    ~ArrayStack(){
        delete[] stack;
    }
    bool empty() const{
        return stackTop==-1;
    }
    int size()const{
        return stackTop+1;
    }
    T& top(){
        if(stackTop==-1){
            throw StackEmpty();
        }
        return stack[stackTop];
    }
    void pop(){
        if(stackTop==-1){
            throw StackEmpty();
        }
        stack[stackTop--].~T();
    }
    void push(const T& theElement);
    void clear(){
        stackTop = -1;
    }
    string toString() const{
        ostringstream s;
        s<<'<';
        int i;
        for(i = 0;i<stackTop;i++){
            s<<stack[i]<<" ";
        }
        if(stackTop!=-1){
            s<<stack[i];
        }
        s<<'>';
        return s.str();
    }
    template<class Y>
    friend ostream& operator<<(ostream& out,ArrayStack<Y>& stack);
private:
    int stackTop;
    int arrayLength;
    T* stack;
};

template<class T>
ArrayStack<T>::ArrayStack(int initialCapacity) {
    if(initialCapacity<1){
        ostringstream s;
        s<<"Initial capacity = "<<initialCapacity<<" must be > 0";
        throw illegalParameterValue(s.str());
    }
    arrayLength = initialCapacity;
    stack = new T[arrayLength];
    stackTop = -1;
}

template<class T>
void ArrayStack<T>::push(const T &theElement) {
    if(stackTop==arrayLength-1){
        changeLength1D(stack,arrayLength,2*arrayLength);
        arrayLength *= 2;
    }
    stack[++stackTop] = theElement;
}

template<class Y>
ostream &operator<<(ostream &out, ArrayStack<Y> &stack) {
    cout<<stack.toString();
    return out;
}


#endif //ALGORITHMS_ARRAYSTACK_H
